from __future__ import annotations

from typing import Iterable, List, Sequence, TypeVar
import argparse


T = TypeVar("T")


def bubble_sort(values: Sequence[T], reverse: bool = False) -> List[T]:
    """
    Return a new list containing the items from `values` sorted using the
    bubble sort algorithm.

    This implementation is stable and stops early if the list is already sorted.

    Parameters
    ----------
    values: Sequence[T]
        The input sequence to sort. It is not modified.
    reverse: bool
        If True, sort in descending order. Default is ascending.

    Returns
    -------
    List[T]
        A new list with the items sorted.
    """
    items: List[T] = list(values)
    n: int = len(items)
    if n < 2:
        return items

    # Comparator direction
    def out_of_order(a: T, b: T) -> bool:
        return a < b if reverse else a > b

    # Perform passes until no swaps occur
    for pass_index in range(n - 1):
        swapped: bool = False
        # After each pass, the largest/smallest element is at the end/beginning
        # Reduce inner loop boundary accordingly
        for i in range(0, n - 1 - pass_index):
            if out_of_order(items[i], items[i + 1]):
                items[i], items[i + 1] = items[i + 1], items[i]
                swapped = True
        if not swapped:
            break
    return items


def parse_numbers(iterable: Iterable[str]) -> List[int]:
    numbers: List[int] = []
    for token in iterable:
        token = token.strip().replace(",", " ")
        if not token:
            continue
        for part in token.split():
            numbers.append(int(part))
    return numbers


def run_tests() -> None:
    """Run simple correctness tests for bubble_sort."""
    test_cases = [
        # (input, reverse, expected)
        ([5, 3, 9, 1, 4], False, [1, 3, 4, 5, 9]),
        ([5, 3, 9, 1, 4], True, [9, 5, 4, 3, 1]),
        ([], False, []),
        ([1], False, [1]),
        ([3, 3, 2, 2, 1], False, [1, 2, 2, 3, 3]),
        ([-1, 5, 0, -3], False, [-3, -1, 0, 5]),
        ([1, 2, 3, 4], False, [1, 2, 3, 4]),  # already sorted
    ]

    for idx, (data, rev, expected) in enumerate(test_cases, start=1):
        result = bubble_sort(data, reverse=rev)
        assert result == expected, f"Case {idx} failed: {data} rev={rev} -> {result}, expected {expected}"

    print("All tests passed (", len(test_cases), "cases).", sep="")


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Bubble sort: reads integers and prints sorted output",
    )
    parser.add_argument(
        "numbers",
        nargs="*",
        help="Integers to sort. If omitted, reads from stdin (space/comma separated).",
    )
    parser.add_argument(
        "--desc",
        action="store_true",
        help="Sort in descending order (default ascending).",
    )
    parser.add_argument(
        "--test",
        action="store_true",
        help="Run built-in tests and exit.",
    )
    args = parser.parse_args()

    if args.test:
        run_tests()
        return

    if args.numbers:
        numbers = [int(x) for x in args.numbers]
    else:
        numbers = parse_numbers(iterable=[input_str for input_str in [input("Enter numbers: ")]])

    sorted_numbers = bubble_sort(numbers, reverse=args.desc)
    print(" ".join(str(x) for x in sorted_numbers))


if __name__ == "__main__":
    main()


